#pragma once

#include "Scene.h"
#include "GUIManager.h"
#include <gl/freeglut.h>
using namespace egg;
using namespace cv;

extern uint32 CANVAS_WIDTH;
extern uint32 CANVAS_HEIGHT;
extern uint32 gPreMouse[2];
extern uint32 gCurMouse[2];
extern bool gButtonDown[3];
extern bool gKeyDown[256];

class PerformanceInfoTray{
public:
    PerformanceInfoTray(){
        using namespace MyGUI;
        mInterval=2.0;
        Gui* gui=GUIManager::getSingletonPtr()->getGUI();
        mTextBox=gui->createWidget<TextBox>("TextBox",0,0,100,100,Align::Center,"Overlapped");
    }

    void update(const FrameEvent& _evt,const RenderContext& _context){
        mInterval+=_evt.getInterval();
        if(mInterval>0.5){
            string info="FPS:"+StringUtil::toString<uint32>(_evt.getFPS());
            info.append("\nDrawcall:"+StringUtil::toString<uint32>(_context.mDrawCallCount));
            info.append("\nTriangle:"+StringUtil::toString<uint32>(_context.mTriangleCount));
            mTextBox->setCaption(info);
            mInterval=0.0;
        }
    }
protected:
    float mInterval;
    MyGUI::TextBox* mTextBox;
};

class EggApp{
public:
    ~EggApp(){

    }

    void init(){
        mRenderer=Renderer::getSingletonPtr();
        mRenderer->startup();
        mScene=new Scene();
        mGUIManager=GUIManager::getSingletonPtr();
        mGUIManager->startup();
        mGUIManager->setSize(CANVAS_WIDTH,CANVAS_HEIGHT);
        mPerformanceInfoTray=new PerformanceInfoTray();
        setupLights();
        setupCamera();
        setupDisplay();
    }

    void render(){
        onRenderBegin();
        mScene->runFrame();
        mGUIManager->runFrame();
        onRendering();
        onRenderEnd();
    }

    virtual void onKeyboard(unsigned char kc,int x,int y){}

    virtual void onMouseDown(int button,int x,int y){}

    virtual void onMouseUp(int button,int x,int y){}

    virtual void onMouseMove(int x,int y){
        const FrameEvent& evt=mScene->getFrameEvent();
        mGUIManager->getInputManager()->injectMouseMove(x,y,0);
        if(gButtonDown[GLUT_LEFT_BUTTON]){
            vec3 curPos=mCamera->getCamera()->vpt2eye(vec3(float(x)/float(CANVAS_WIDTH),y,1));
            vec3 prePos=mCamera->getCamera()->vpt2eye(vec3(gPreMouse[0],gPreMouse[1],1));
            vec3 dir=glm::normalize(curPos-prePos);
            mCamera->translate(-dir*evt.getInterval(),TS_LOCAL);
        }else if(gButtonDown[GLUT_RIGHT_BUTTON]){
            int32 deltaX=x-gPreMouse[0];
            int32 deltaY=y-gPreMouse[1];
            vec3 axis(-deltaY,-deltaX,0);
            mCamera->rotate(evt.getInterval()*45.0f,axis,TS_LOCAL);
        }
    }

    virtual void onMouseWheel(int button,int delta,int x,int y){
        const FrameEvent& evt=mScene->getFrameEvent();
        if(delta>0){
            mCamera->getCamera()->forward(-5.0f*evt.getInterval());
        }else{
            mCamera->getCamera()->forward(5.0f*evt.getInterval());
        }
    }

protected:
    virtual void onRenderBegin(){

    }

    virtual void onRendering(){
    }

    virtual void onRenderEnd(){
        mPerformanceInfoTray->update(
            mScene->getFrameEvent(),
            mRenderer->getContext());
    }

    virtual void setupCamera(){
        mCamera=new CameraActor();
        mCamera->getCamera()->setFar(100.0);
        mCamera->getCamera()->setNear(0.1);
        mCamera->getCamera()->forward(4.0);
        mCamera->addTo(mScene->getRoot());
        mWindow=RenderTargetPtr(new RenderWindow(CANVAS_WIDTH,CANVAS_HEIGHT));
        Viewport* vp=mCamera->getCamera()->getViewport();
        vp->mTarget=mWindow;
        vp->mWidth=CANVAS_WIDTH;
        vp->mHeight=CANVAS_HEIGHT;
        vp->mColor=vec4(0.3,0.2,0.1,0);
    }

    virtual void setupLights(){
    }

    virtual void setupDisplay(){
    }

protected:
    GUIManagerPtr mGUIManager;
    RendererPtr mRenderer;
    RenderTargetPtr mWindow;
    Scene* mScene;
    CameraActor* mCamera;
    PerformanceInfoTray* mPerformanceInfoTray;
    float mInterval;
};